/**
 * Copyright (C) 2008 aileron.cc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package cc.aileron.commons.initialize;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;


/**
 * 
 * @author Aileron
 *
 * @param <T>
 */
public class SuperInitializer <T>
{
    /**
     * initialize 対象の Class を生成
     * @return
     * @throws ConcreateInitilalizeException
     */
    public T concreate() 
    throws ConcreateInitilalizeException
    {
        try
        {
            this.tryInitializeCheck();
            return this.tryNewInstance();
        }
        catch(Exception e)
        {
            throw new ConcreateInitilalizeException(e);
        }
    }
    
    /**
     * 未定義のフィールドをチェックする
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws ConcreateInitilalizeException
     */
    private void tryInitializeCheck() 
    throws IllegalArgumentException
        , IllegalAccessException
        , ConcreateInitilalizeException
    {
        for(final Field field : this.getClass().getFields())
        {
            if(field.get(this)==null)
            {
                throw new ConcreateInitilalizeException("field undefined is [ " + field.getName() + " ]");
            }
        }
    }
    
    /**
     * newInstance
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     */
    @SuppressWarnings("unchecked")
    private T tryNewInstance() 
    throws InstantiationException
        , IllegalAccessException
        , SecurityException
        , NoSuchMethodException
        , IllegalArgumentException
        , InvocationTargetException
    {
        final Type t = this.getClass().getGenericSuperclass();
        final Class<T> c = (Class<T>)((ParameterizedType) t).getActualTypeArguments()[0];
        return c.getConstructor(this.getClass()).newInstance(this);
    }
}